package parser;

import scanner.*;
import scanner.Scanner;

import java.util.*;

public abstract class BaseParser
    implements Observer
{
    protected Token currentToken;
    protected scanner.Scanner scanner;
    private boolean wasError;

    public BaseParser(Scanner scanner)
    {
        this.scanner = scanner;
    }

    public abstract SyntaxNode Parse();

    protected SyntaxNode ParseIdentifier()
    {
        SyntaxNode node = null;
        if (currentToken.GetId() == TokenId.IDENTIFIER)
        {
            node = new SyntaxNode(SyntaxNodeType.ID, currentToken.GetData());
        }
        else
        {
            HandleError("identifier expected");
        }
        return node;
    }

    protected void CheckSpecificToken(TokenId tokenId)
    {
        if (currentToken.GetId() != tokenId)
        {
            String tokenStr = scanner.GetTokenAsString(tokenId);
            HandleError("'" + tokenStr + "' expected");
        }
    }

    protected void ReadSpecificToken(TokenId tokenId)
    {
        CheckSpecificToken(tokenId);
        ReadToken();
    }

    public boolean WasError()
    {
        return wasError;
    }

    public void update(Observable observable, Object arg)
    {
        wasError = true;
        System.out.println(arg);
    }

    protected void HandleError(String errorMessage)
    {
        wasError = true;
        System.out.println("Syntax error at line " + scanner.GetCurrentLine() + ": " + errorMessage);
    }

    protected void ReadToken()
    {
        do
        {
            currentToken = scanner.Read();
        }
        while (currentToken.GetId() == TokenId.COMMENT);
    }

    protected void PeekToken()
    {
        Token peekToken = scanner.Peek();
        while (peekToken.GetId() == TokenId.COMMENT)
        {
            scanner.Read();
            peekToken = scanner.Peek();
        }
        currentToken = peekToken;
    }

    protected boolean IsTokenNext(TokenId... tokenIds)
    {
        boolean isTokenNext = false;
        PeekToken();
        for (TokenId tokenId : tokenIds)
        {
            if (tokenId == currentToken.GetId())
            {
                isTokenNext = true;
            }
        }
        if (isTokenNext)
        {
            ReadToken();
        }
        return isTokenNext;
    }
}
